Imports agsXMPP
Imports agsXMPP.protocol
Imports agsXMPP.protocol.extensions
Imports agsXMPP.protocol.client
Imports agsXMPP.protocol.iq.roster

Namespace gtalkNotepad
	Public Class Chat

		Private m_xmppClientConnection As XmppClientConnection
		Private m_hashRoster As New Hashtable
		Private m_isLoggedIn As Boolean = False
		Private m_haveRoster As Boolean = False
		Private m_contacts As New Contacts
		Private m_status As Contact.ContactStatus

		''' <summary>
		''' If the user is logged into the chat server.
		''' </summary>
		Public ReadOnly Property IsLoggedIn() As Boolean
			Get
				Return m_isLoggedIn And m_xmppClientConnection.Authenticated
			End Get
		End Property

		''' <summary>
		''' If the roster has been downloaded.
		''' </summary>
		Public ReadOnly Property HaveRoster() As Boolean
			Get
				Return m_haveRoster
			End Get
		End Property

		''' <summary>
		''' The roster containing the online contacts for the currently logged in user.
		''' </summary>
		Public ReadOnly Property Roster() As Hashtable
			Get
				Return m_hashRoster
			End Get
		End Property

		Public ReadOnly Property Contacts() As Contacts
			Get
				Return m_contacts
			End Get
		End Property

		Public ReadOnly Property Status() As Contact.ContactStatus
			Get
				Return m_status
			End Get
		End Property


		''' <summary>
		''' Fires when a chat response has been recieved.
		''' </summary>
		''' <remarks>This generaly fires when this object wants to output data to the user.</remarks>
		Public Event OnChatResponse(ByVal sender As Object, ByVal e As ChatResponseEventArgs)

		''' <summary>
		''' Fires when the roster has been downloaded.
		''' </summary>
		Public Event OnRosterLoad()

		Public Event OnContactStatusChange(ByVal sender As Object, ByVal status As Contact.ContactStatus)

		''' <summary>
		''' Constructor. Initializes an xmppClientConnection.
		''' </summary>
		''' <param name="server"></param>
		''' <param name="port"></param>
		''' <param name="connectServer"></param>
		''' <param name="username"></param>
		''' <param name="password"></param>
		''' <param name="useSSL"></param>
		''' <remarks></remarks>
		Public Sub New(ByVal server As String, ByVal port As Int32, ByVal connectServer As String, ByVal username As String, ByVal password As String, ByVal resource As String, ByVal useSSL As Boolean)
			m_xmppClientConnection = New XmppClientConnection(server, port)

			AddHandler m_xmppClientConnection.OnError, AddressOf xmpp_OnError
			AddHandler m_xmppClientConnection.OnLogin, AddressOf xmpp_OnLogin
			AddHandler m_xmppClientConnection.OnMessage, AddressOf xmpp_OnMessage
			AddHandler m_xmppClientConnection.OnRosterStart, AddressOf xmpp_OnRosterStart
			AddHandler m_xmppClientConnection.OnRosterItem, AddressOf xmpp_OnRosterItem
			AddHandler m_xmppClientConnection.OnRosterEnd, AddressOf xmpp_OnRosterEnd
			AddHandler m_xmppClientConnection.OnPresence, AddressOf xmpp_OnPresence
			AddHandler m_xmppClientConnection.OnReadXml, AddressOf xmpp_OnReadXml
			AddHandler m_xmppClientConnection.OnWriteXml, AddressOf xmpp_OnWriteXml

			m_xmppClientConnection.ConnectServer = connectServer
			m_xmppClientConnection.Username = username
			m_xmppClientConnection.Password = password
			m_xmppClientConnection.UseSSL = useSSL
			m_xmppClientConnection.Resource = resource
			m_xmppClientConnection.AutoRoster = False

		End Sub



		''' <summary>
		''' Logs the user into the chat server.
		''' </summary>
		''' <remarks></remarks>
		Public Sub Login()
			m_isLoggedIn = False
			m_xmppClientConnection.Open()
		End Sub

		''' <summary>
		''' Sends a chat state message to a user.
		''' </summary>
		''' <param name="sendTo">User to send the chat state to.</param>
		''' <param name="state">The chat state to send.</param>
		''' <remarks></remarks>
		Public Sub SendState(ByRef sendTo As Contact, ByVal state As chatstates.Chatstate)
			sendChat(sendTo, String.Empty, state)
			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Status, "Changing current state to " & state.ToString(), "", ChatVerbosity.High))
		End Sub

		''' <summary>
		''' Sends a message to a user.
		''' </summary>
		''' <param name="sendTo">User to send the message to.</param>
		''' <param name="text">Text to send.</param>
		''' <remarks></remarks>
		Public Sub SendMessage(ByRef sendTo As Contact, ByVal text As String)
			sendChat(sendTo, text, chatstates.Chatstate.active)
			'RaiseEvent OnChatResponse("Me: " & text)
		End Sub

		Public Sub SetStatus(ByVal status As Contact.ContactStatus, Optional ByRef sendTo As Contact = Nothing)
			If m_isLoggedIn Then
				Select Case status
					Case Contact.ContactStatus.Active
						m_xmppClientConnection.Show = ShowType.chat
						m_xmppClientConnection.SendMyPresence()
						m_status = status
					Case Contact.ContactStatus.Dnd
						m_xmppClientConnection.Show = ShowType.dnd
						m_xmppClientConnection.SendMyPresence()
						m_status = status
					Case Contact.ContactStatus.ExtendedAway
						m_xmppClientConnection.Show = ShowType.xa
						m_xmppClientConnection.SendMyPresence()
						m_status = status
					Case Contact.ContactStatus.Idle
						m_xmppClientConnection.Show = ShowType.away
						m_xmppClientConnection.SendMyPresence()
						m_status = status
					Case Contact.ContactStatus.Disconnected
						If Not sendTo Is Nothing Then
							sendChat(sendTo, String.Empty, chatstates.Chatstate.gone)
						End If
					Case Contact.ContactStatus.Typing
						If Not sendTo Is Nothing Then
							sendChat(sendTo, String.Empty, chatstates.Chatstate.composing)
						End If
					Case Contact.ContactStatus.Paused
						If Not sendTo Is Nothing Then
							sendChat(sendTo, String.Empty, chatstates.Chatstate.paused)
						End If
				End Select
				RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Status, "Changing current state to " & status.ToString(), "", ChatVerbosity.High))
			End If
		End Sub

		Private Sub sendChat(ByRef sendTo As Contact, ByVal text As String, ByVal state As chatstates.Chatstate)
			If Me.IsLoggedIn Then
				Dim msg As New Message()

				msg.Type = MessageType.chat
				msg.To = sendTo.Jid
				msg.From = m_xmppClientConnection.MyJID
				msg.Chatstate = state
				msg.Thread = sendTo.ThreadId
				If Not String.IsNullOrEmpty(text) Then msg.Body = text

				m_xmppClientConnection.Send(msg)
			End If
		End Sub

		Private Sub xmpp_OnWriteXml(ByVal sender As Object, ByVal xml As String)
			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.XmlWrite, xml, "", ChatVerbosity.RawXML))
		End Sub

		Private Sub xmpp_OnReadXml(ByVal sender As Object, ByVal xml As String)
			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.XmlRead, xml, "", ChatVerbosity.RawXML))
		End Sub

		Private Sub xmpp_OnPresence(ByVal sender As Object, ByVal pres As Presence)
			Dim status As Contact.ContactStatus = Contact.ContactStatus.Disconnected

			Select Case pres.Type
				Case PresenceType.available
					Select Case pres.Show
						Case ShowType.away : status = Contact.ContactStatus.Idle
						Case ShowType.chat : status = Contact.ContactStatus.Active
						Case ShowType.dnd : status = Contact.ContactStatus.Dnd
						Case ShowType.xa : status = Contact.ContactStatus.ExtendedAway
						Case ShowType.NONE : status = Contact.ContactStatus.Active
						Case Else : status = Contact.ContactStatus.Idle
					End Select
				Case PresenceType.unavailable : status = Contact.ContactStatus.Disconnected
			End Select
			

			If Not m_contacts.ContainsJid(pres.From.ToString()) Then
				m_contacts.Add(pres.From.ToString(), New Contact(pres.From))
			End If
			m_contacts(pres.From.ToString()).Status = status

			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Status, pres.From.ToString & " status changed to " & status.ToString(), "", ChatVerbosity.Medium))
		End Sub

		Private Sub xmpp_OnRosterEnd(ByVal sender As Object)
			'm_haveRoster = True
			'RaiseEvent OnRosterLoad()
		End Sub

		Private Sub xmpp_OnRosterItem(ByVal sender As Object, ByVal ri As agsXMPP.protocol.iq.roster.RosterItem)
			'Turns out I don't care about the roster, just the active users who come through on the onPresence event.
			'If Not ri.Jid Is Nothing Then
			'	If Not m_contacts.ContainsJid(ri.Jid.ToString()) Then
			'		m_contacts(ri.Jid.ToString()) = New Contact(ri.Jid)
			'	End If
			'End If

		End Sub

		Private Sub xmpp_OnRosterStart(ByVal sender As Object)
			'm_contacts.Clear()
			'm_hashRoster.Clear()
		End Sub

		Private Sub xmpp_OnError(ByVal sender As Object, ByVal ex As System.Exception)
			Dim text As String = "Error: " & ex.Message
			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.ErrorMessage, ex.Message))
		End Sub

		Private Sub xmpp_OnMessage(ByVal sender As Object, ByVal msg As agsXMPP.protocol.client.Message)
			If Not msg.From Is Nothing Then
				Dim jid As String = msg.From.ToString()
				If Not m_contacts.ContainsJid(jid) Then
					m_contacts.Add(jid, New Contact(msg.From))
				End If

				Select Case msg.Chatstate
					Case agsXMPP.protocol.extensions.chatstates.Chatstate.active
						m_contacts(jid).IsActive = True
						m_contacts(jid).Status = Contact.ContactStatus.Active
						If Not String.IsNullOrEmpty(msg.Body) Then
							' Google talk doesn't seem to use message threads. Interesting.
							If Not String.IsNullOrEmpty(msg.Thread) Then m_contacts(jid).ThreadId = msg.Thread
							If msg.From.User = "brianwagener" And msg.From.Server = "gmail.com" Then
								RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Chat, msg.Body, "God"))
							Else
								RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Chat, msg.Body, msg.From.User))
							End If
						End If
					Case agsXMPP.protocol.extensions.chatstates.Chatstate.composing
						m_contacts(jid).Status = Contact.ContactStatus.Typing
					Case agsXMPP.protocol.extensions.chatstates.Chatstate.paused
						m_contacts(jid).Status = Contact.ContactStatus.Paused
					Case chatstates.Chatstate.gone
						m_contacts(jid).Status = Contact.ContactStatus.Disconnected
						m_contacts(jid).IsActive = False
					Case chatstates.Chatstate.inactive
						m_contacts(jid).Status = Contact.ContactStatus.Idle
						m_contacts(jid).IsActive = False
					Case chatstates.Chatstate.None
						m_contacts(jid).Status = Contact.ContactStatus.Disconnected
				End Select
			End If
		End Sub

		Private Sub xmpp_OnLogin(ByVal sender As Object)
			Dim _settings As New Settings()
			m_isLoggedIn = True
			'm_haveRoster = False
			m_xmppClientConnection.SendMyPresence()
			m_xmppClientConnection.KeepAliveInterval = _settings.KeepAlive
			m_xmppClientConnection.KeepAlive = True

			RaiseEvent OnChatResponse(Me, New ChatResponseEventArgs(ChatResponses.Status, "Logged In as " & m_xmppClientConnection.MyJID.ToString()))
			'm_xmppClientConnection.RequestRoster()
		End Sub

	End Class
End Namespace
